

#include "gpioDriver.h"

#include "uart.h"

#include "modbus.h"

#include "i2cDriver.h"

#include "ds1307Driver.h"

#include "PCF8575Driver.h"

#include <avr/interrupt.h>

#include <avr/io.h>

#define F_CPU 3686400
#include <util/delay_basic.h>

#define PD 0x12
#define DDD 0x11

#define PA 0x1B
#define DDA 0x1A


#define ADD 1
#define NUM_REGISTERS 20

#define UART_BAUD_RATE      9600    

sWord * readRegisters(sWord * registers, sWord * returnedRegisters, int start,int numWords);
int initializeRegisters(sWord * registers);
int copyRegisters(sWord * source, sWord * destination, int shift, int len);
unsigned char * get8Bytes(unsigned char * dataIn);
int addToBuffer(unsigned char * buffer, unsigned char * dataIn, int start, int len);
sWord writeSingleRegister(unsigned short * registers, sWord address, sWord value);
void updateValues(unsigned short * registers);

int main()
{
 	setPortsDirection(); // Configure ports
	rtcInit(); // Initialize the RTC
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); // Initialize UART
    sei(); // Enable global interrupts

	rtcSetTime(0x19,0x25,0x55); // Set RTC time
	rtcSetDate(0x11,0x4,0x28);

	unsigned char dataOut[100] = {0}; // Data out buffer
	unsigned char dataIn[8] = {0};	// Data in buffer, fixed to 8 bits

	unsigned char tempData[8] = {0};

	unsigned short registers[NUM_REGISTERS] = {0}; // Station registers

	initializeRegisters(registers);

	mbPacket tempPacket;
	mbPacket responsePacket;


	
	sWord testResponse[2] = {0};

	sWord tempCRC = {0};
	tempCRC.Word = 0x336A;


	sWord returnedRegisters[NUM_REGISTERS] = {0};



	uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); // Initialize UART
    sei(); // Enable global interrupts

	PORTA = 0xFF;
	

	while(1)
	{
		
	//	read(dataIn,9); // Working properly

		


		read2(tempData,2);

		dataIn[0] = tempData[0];
		dataIn[1] = tempData[1];
		
		read2(tempData,6);

		dataIn[2] = tempData[0];
		dataIn[3] = tempData[1];
		dataIn[4] = tempData[2];
		dataIn[5] = tempData[3];
		dataIn[6] = tempData[4];
		dataIn[7] = tempData[5];


		int shift = 0;

		tempPacket = deserializeMBpacket(dataIn);


		// To be checked packet integrity


		// Create packet reply

		switch(tempPacket.header.op)
		{

			case read_register: // op code 3
					
				if (tempPacket.tail.readPacketRequest.numWord.Word > 0)
				{
					readRegisters(registers,returnedRegisters,tempPacket.tail.readPacketRequest.startWord.Word,tempPacket.tail.readPacketRequest.numWord.Word); // Returns the read words in the returned registers array
				
					dataOut[0] = ADD;
					dataOut[1] = read_register; // op
					dataOut[2] = tempPacket.tail.readPacketRequest.numWord.Word * 2; // num bytes

					shift = copyRegisters(returnedRegisters,dataOut,3,tempPacket.tail.readPacketRequest.numWord.Word);
				
					// Compute CRC
					 tempCRC.Word = crc16(dataOut,tempPacket.tail.readPacketRequest.numWord.Word*2+3); // Calculate CRC of the message;

					 shift = tempPacket.tail.readPacketRequest.numWord.Word * 2 + 3;
					dataOut[shift] = tempCRC.Bytes.ByteLo;
					dataOut[shift+1] = tempCRC.Bytes.ByteHi;

					// Write to the serial port
					write(dataOut,shift+3);

				}

				break;


			case write_register: // Write a single register
				

				writeSingleRegister(registers,tempPacket.tail.writeSingleRegRequest.startWord,tempPacket.tail.writeSingleRegRequest.data);


				dataOut[0] = ADD;
				dataOut[1] = write_register;
				dataOut[2] = tempPacket.tail.writeSingleRegRequest.startWord.Bytes.ByteHi;
				dataOut[3] = tempPacket.tail.writeSingleRegRequest.startWord.Bytes.ByteLo;
				dataOut[4] = tempPacket.tail.writeSingleRegRequest.data.Bytes.ByteHi;
				dataOut[5] = tempPacket.tail.writeSingleRegRequest.data.Bytes.ByteLo;

				tempCRC.Word = crc16(dataOut,6);
				dataOut[6] = tempCRC.Bytes.ByteLo;
				dataOut[7] = tempCRC.Bytes.ByteHi;
				
				//PORTA = registers[1];
				write(dataIn,9);

				break;

			case write_registers:

				dataOut[0] = 0x1;
				dataOut[1] = 0x3;
								
				write(dataOut,3);

				break;

		}

		updateValues(registers);

	}

	return 0;
}

void updateValues(unsigned short * registers)
{
	unsigned char h,m,s;
	unsigned char y,mn,d;

	registers[0] = NUM_REGISTERS;

	registers[1] = portADirection;
	PORTA = registers[2];

	registers[3] = portBDirection;
	registers[4] = PINB;

	registers[5] = portCDirection;
	registers[6] = PINC;


	registers[7] = portDDirection;
	registers[8] = PIND;

	writeIOExpander(registers[10],registers[12]);
	

	rtcGetTime(&h,&m,&s); // Get time

	registers[13] = s;
	registers[14] = m;
	registers[15] = h;

	rtcGetDate(&y,&mn,&d);

	registers[16] = d;
	registers[17] = mn;
	registers[18] = y;

}


sWord writeSingleRegister(unsigned short * registers, sWord address, sWord value)
{
	registers[address.Word] = value.Word;
	return value;
}

unsigned char * get8Bytes(unsigned char * dataIn)
{


		//read(tempData,3);

		dataIn[0] = uart_getc();
		dataIn[1] = uart_getc();

		//read(tempData,5);

		dataIn[2] = uart_getc();
		dataIn[3] = uart_getc();
		dataIn[4] = uart_getc();
		dataIn[5] = uart_getc();
		dataIn[6] = uart_getc();
		dataIn[7] = uart_getc();


	return dataIn;
}



int copyRegisters(sWord * source, sWord * destination, int shift, int len)
{
	int i=0;
	
	for(i = 0; i< len;i++)
	{
		destination[i+shift-1].Bytes.ByteHi = source[i].Bytes.ByteHi;
		destination[i+shift-1].Bytes.ByteLo = source[i].Bytes.ByteLo;
	}	

	return i+shift;
}

sWord * readRegisters(sWord * registers, sWord * returnedRegisters, int start,int numWords)
{

	int i = 0;

	for(i = 0; i < numWords; i++)
	{
		returnedRegisters[i].Word = registers[i+start].Word;
	}

	return returnedRegisters;
}

int checkIntegrity(unsigned char pState)
{
	return 1;	
}

int initializeRegisters(sWord * registers)
{
	unsigned short i = 0;
	
	for(i=0;i<NUM_REGISTERS;i++)
	{
		registers[i].Word = 0x00;
	}

	return i;
}


void clearBuffer(unsigned char * buffer, int lenght)
{
	int i=0;

	for(i=0;i<lenght;i++)
	{
		buffer[i] = 0;
	}

}

int addToBuffer(unsigned char * buffer, unsigned char * dataIn, int start, int len)
{
	int i = 0;
	for(i=0;i<len;i++)
	{
		buffer[i+start]=dataIn[i];
	}
	return start+len;
}





